Now progressive gif loading works! It's a little slow though. )-:
authorJonathan Blandford <jrb@redhat.com>
Tue, 2 Nov 1999 23:49:22 +0000 (23:49 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Tue, 2 Nov 1999 23:49:22 +0000 (23:49 +0000)
1999-11-02  Jonathan Blandford  <jrb@redhat.com>

* src/io-gif.c (gif_main_loop): Now progressive gif loading works!
It's a little slow though. )-:

demos/testpixbuf.c
gdk-pixbuf/ChangeLog
gdk-pixbuf/Makefile.am
gdk-pixbuf/io-gif.c

index 350b4cba1eef095d3037f711c470821cb60baf99..4fedda2b9205c8853fb59f0f7a2bace63af95016 100644 (file)
@@ -520,7 +520,7 @@ main (int argc, char **argv)
                                int nbytes;
                                nbytes = fread(buf, 1, readlen, file);
 
-                                printf(".");
+/*                                printf(".");*/
                                 fflush(stdout);
                                 
                                 if (gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (pixbuf_loader), buf, nbytes) == FALSE)
@@ -529,7 +529,7 @@ main (int argc, char **argv)
                                while (gtk_events_pending())
                                        gtk_main_iteration();
                         }
-                       printf("\n");
+/*                     printf("\n");*/
                        gtk_timeout_remove (timeout);
                         gdk_pixbuf_loader_close (GDK_PIXBUF_LOADER (pixbuf_loader));
                        gtk_object_destroy (GTK_OBJECT(pixbuf_loader));
index 57ba7c401a82a55c24a7d959f9ccae2b645b9901..c9e863254a534dc69aaaa49e8d5258e9540f098e 100644 (file)
@@ -1,3 +1,8 @@
+1999-11-02  Jonathan Blandford  <jrb@redhat.com>
+
+       * src/io-gif.c (gif_main_loop): Now progressive gif loading works!
+       It's a little slow though. )-:
+
 1999-11-02 Elliot Lee <sopwith@redhat.com>
        * src/gdk-pixbuf-loader.[ch], src/gdk-pixbuf-io.h: Make the arguments to the
        write/load_increment operations const-correct.
index 79a0eb4ee03c1765290767dc80423539431e995a..63fdd512b645f1166c4969c06acd6cd2612284ed 100644 (file)
@@ -37,7 +37,7 @@ AM_CPPFLAGS = "-DPIXBUF_LIBDIR=\"$(libexecdir)\""
 
 LDADDS = libgdk_pixbuf.la $(LIBART_LIBS) $(GLIB_LIBS)
 
-testpixbuf_LDADD = $(LDADDS) $(LIBART_LIBS)
+testpixbuf_LDADD = $(LDADDS) $(LIBART_LIBS) -lgnomeui -lart_lgpl -lgdk_imlib  -lgtk -lgdk -lgmodule -lgnome -lgnomesupport
 
 #
 # The GdkPixBuf library
index 86969e9bb8e8fb9dbd4d7ecef1ffa4c425c9cd67..cd2221a1b87873221dc97a622d4552df7836d43e 100644 (file)
@@ -54,13 +54,15 @@ typedef unsigned char CMap[3][MAXCOLORMAPSIZE];
 /* Possible states we can be in. */
 enum {
        GIF_START = 1,
-       GIF_GET_COLORMAP = 2,
-       GIF_GET_NEXT_STEP = 3,
-       GIF_GET_EXTENTION = 4,
-       GIF_GET_COLORMAP2 = 5,
-       GIF_PREPARE_LZW = 6,
-       GIF_GET_LZW = 7,
-       GIF_DONE = 8
+       GIF_GET_COLORMAP,
+       GIF_GET_NEXT_STEP,
+       GIF_GET_FRAME_INFO,
+       GIF_GET_EXTENTION,
+       GIF_GET_COLORMAP2,
+       GIF_PREPARE_LZW,
+       GIF_LZW_FILL_BUFFER,
+       GIF_GET_LZW,
+       GIF_DONE,
 };
 
 
@@ -105,20 +107,26 @@ struct _GifContext
        guint size;
        guint amount_needed;
 
-       /* our colormap context */
+       /* colormap context */
        gint colormap_index;
        gint colormap_flag;
 
-       /* our extension context */
+       /* extension context */
        guchar extension_label;
        guchar extension_flag;
 
        /* get block context */
        guchar block_count;
-       guchar block_buf[256];
+       guchar block_buf[280];
        gint block_ptr;
 
-       /* our lwz context */
+       /* get_code context */
+       int code_curbit;
+       int code_lastbit;
+       int code_done;
+       int code_last_byte;
+       
+       /* lwz context */
        gint lwz_fresh;
        gint lwz_code_size;
        guchar lwz_set_code_size;
@@ -131,40 +139,71 @@ struct _GifContext
        gint lwz_table[2][(1 << MAX_LWZ_BITS)];
        gint lwz_stack[(1 << (MAX_LWZ_BITS)) * 2];
        gint *lwz_sp;
+
+       /* painting context */
+       gint draw_xpos;
+       gint draw_ypos;
+       gint draw_pass;
 };
 
 static int GetDataBlock (GifContext *, unsigned char *);
-static int GetCode (GifContext *, int, int);
-static int LWZReadByte (GifContext *);
+static int GetCode (GifContext *, int);
 
+/* Returns TRUE if Read is OK,
+ * FALSE if more memory is needed. */
+static int count = 0;
 static int
 ReadOK (GifContext *context, guchar *buffer, size_t len)
 {
-       static int count = 0;
-       count += len;
-       g_print ("size :%d\tcount :%d\n", len, count);
-       if (context->file)
-               return fread(buffer, len, 1, context->file) != 0;
-       else {
-               if ((context->size - context->ptr) < len) {
+       gint retval, i;
+       if (context->file) {
+               count += len;
+#ifdef IO_GIFDEBUG
+               g_print ("Fsize :%d\tcount :%d\t", len, count);
+#endif
+               retval = (fread(buffer, len, 1, context->file) != 0);
+#ifdef IO_GIFDEBUG
+               if (len < 100) {
+                       for (i = 0; i < len; i++)
+                               g_print ("%d ", buffer[i]);
+               }
+               g_print ("\n");
+#endif
+               return retval;
+       } else {
+#ifdef IO_GIFDEBUG
+               g_print ("\tlooking for %d bytes.  size == %d, ptr == %d\n", len, context->size, context->ptr);
+#endif
+               if ((context->size - context->ptr) >= len) {
+                       count += len;
                        memcpy (buffer, context->buf + context->ptr, len);
                        context->ptr += len;
                        context->amount_needed = 0;
-                       return 0;
+#ifdef IO_GIFDEBUG
+                       g_print ("Psize :%d\tcount :%d\t", len, count);
+                       if (len < 100) {
+                               for (i = 0; i < len; i++)
+                                       g_print ("%d ", buffer[i]);
+                       }
+                       g_print ("\n");
+#endif
+                       return TRUE;
                }
                context->amount_needed = len - (context->size - context->ptr);
        }
-       return 1;
+       return 0;
 }
 
 
 /*
  * Return vals.
+ * Unless otherwise specified, these are the return vals for most functions:
  *
- * for the gif_get* functions,
- *-1 -> more bytes needed.
- * 0 -> success
- * 1 -> failure; abort the load
+ *  0 -> success
+ * -1 -> more bytes needed.
+ * -2 -> failure; abort the load
+ * -3 -> control needs to be passed back to the main loop
+ *        \_ (most of the time returning 0 will get this, but not always)
  */
 
 
@@ -218,7 +257,7 @@ gif_get_colormap (GifContext *context)
  * context->block_count is 0 before we read in the function.
  *
  * As a result, context->block_count MUST be 0 the first time the get_data_block is called
- * within a context.
+ * within a context, and cannot be 0 the second time it's called.
  */
 
 static int
@@ -234,10 +273,10 @@ get_data_block (GifContext *context,
        }
 
        if (context->block_count == 0)
-               if (empty_block)
+               if (empty_block) {
                        *empty_block = TRUE;
-
-       return 0;
+                       return 0;
+               }
 
        if (!ReadOK (context, buf, context->block_count)) {
                return -1;
@@ -249,7 +288,6 @@ get_data_block (GifContext *context,
 static void
 gif_set_get_extension (GifContext *context)
 {
-       g_print ("getting the extension woooooo\n");
        context->state = GIF_GET_EXTENTION;
        context->extension_flag = TRUE;
        context->extension_label = '\000';
@@ -263,7 +301,6 @@ gif_get_extension (GifContext *context)
        gint retval;
        gint empty_block = FALSE;
 
-       g_print ("in gif_get_extension\n");
        if (context->extension_flag) {
                if (!context->extension_label) {
                        if (!ReadOK (context, &context->extension_label , 1)) {
@@ -289,6 +326,7 @@ gif_get_extension (GifContext *context)
                        }
                        
                        /* Now we've successfully loaded this one, we continue on our way */
+                       context->block_count = 0;
                        context->extension_flag = FALSE;
                default:
                        /* Unhandled extension */
@@ -329,62 +367,132 @@ GetDataBlock (GifContext *context,
        return context->block_count;
 }
 
+#if 0
 
 static int
 GetCode (GifContext *context,
-        int   code_size,
-        int   flag)
+        int   code_size)
 {
-       static unsigned char buf[280];
-       static int curbit, lastbit, done, last_byte;
        int i, j, ret;
        unsigned char count;
 
-       if (flag) {
-               curbit = 0;
-               lastbit = 0;
-               done = FALSE;
-               return 0;
-       }
 
-       if ((curbit + code_size) >= lastbit){
-               if (done) {
-                       if (curbit >= lastbit) {
+       if ((context->code_curbit + code_size) >= context->code_lastbit){
+               if (context->code_done) {
+                       if (context->code_curbit >= context->code_lastbit) {
                                /*g_message (_("GIF: ran off the end of by bits\n"));*/
-                               return -1;
+                               return -2;
                        }
-                       return -1;
+                       return -2;
                }
-               buf[0] = buf[last_byte - 2];
-               buf[1] = buf[last_byte - 1];
+               context->block_buf[0] = context->block_buf[context->code_last_byte - 2];
+               context->block_buf[1] = context->block_buf[context->code_last_byte - 1];
 
-               if ((count = GetDataBlock (context, &buf[2])) == 0)
-                       done = TRUE;
+               context->block_count = 0;
+               
+               if ((count = GetDataBlock (context, &context->block_buf[2])) == 0)
+                       context->code_done = TRUE;
 
-               last_byte = 2 + count;
-               curbit = (curbit - lastbit) + 16;
-               lastbit = (2 + count) * 8;
+               context->code_last_byte = 2 + count;
+               context->code_curbit = (context->code_curbit - context->code_lastbit) + 16;
+               context->code_lastbit = (2 + count) * 8;
        }
 
        ret = 0;
-       for (i = curbit, j = 0; j < code_size; ++i, ++j)
-               ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
+       for (i = context->code_curbit, j = 0; j < code_size; ++i, ++j)
+               ret |= ((context->block_buf[i / 8] & (1 << (i % 8))) != 0) << j;
 
-       curbit += code_size;
+       context->code_curbit += code_size;
 
        return ret;
 }
+#endif
+
+static void
+gif_set_lzw_fill_buffer (GifContext *context)
+{
+       context->block_count = 0;
+       context->state = GIF_LZW_FILL_BUFFER;
+}
 
 static int
-LWZReadByte (GifContext *context)
+gif_lzw_fill_buffer (GifContext *context)
+{
+       gint retval;
+       
+       if (context->code_done) {
+               if (context->code_curbit >= context->code_lastbit) {
+                               g_message ("GIF: ran off the end of by bits\n");
+                       return -2;
+               }
+               g_message ("trying to read more data after we've done stuff\n");
+               return -2;
+       }
+
+       context->block_buf[0] = context->block_buf[context->code_last_byte - 2];
+       context->block_buf[1] = context->block_buf[context->code_last_byte - 1];
+
+       retval = get_data_block (context, &context->block_buf[2], NULL);
+
+       if (retval == -1)
+               return -1;
+
+       if (context->block_count == 0)
+               context->code_done = TRUE;
+
+       context->code_last_byte = 2 + context->block_count;
+       context->code_curbit = (context->code_curbit - context->code_lastbit) + 16;
+       context->code_lastbit = (2 + context->block_count) * 8;
+
+       context->state = GIF_GET_LZW;
+       return 0;
+}
+
+static int
+GetCode (GifContext *context,
+        int   code_size)
+{
+       int i, j, ret;
+
+       if ((context->code_curbit + code_size) >= context->code_lastbit){
+               gif_set_lzw_fill_buffer (context);
+               return -3;
+       }
+
+       ret = 0;
+       for (i = context->code_curbit, j = 0; j < code_size; ++i, ++j)
+               ret |= ((context->block_buf[i / 8] & (1 << (i % 8))) != 0) << j;
+
+       context->code_curbit += code_size;
+
+       return ret;
+}
+
+/*
+ * For various reasons, this one is a little different from the others:
+ *
+ * returns -1 if it needs more bytes.
+ * returns -2 if there's an error.
+ * returns -3 if there is no error, but needs to go back to the main loop.
+ * returns the byte otherwise.
+ */
+
+static int
+lwz_read_byte (GifContext *context)
 {
        int code, incode;
+       gint retval;
        register int i;
 
        if (context->lwz_fresh) {
                context->lwz_fresh = FALSE;
                do {
-                       context->lwz_firstcode = context->lwz_oldcode = GetCode (context, context->lwz_code_size, FALSE);
+                       retval = GetCode (context, context->lwz_code_size);
+                       if (retval < 0) {
+                               return retval;
+                       }
+                       
+                       context->lwz_firstcode = context->lwz_oldcode = retval;
                } while (context->lwz_firstcode == context->lwz_clear_code);
                return context->lwz_firstcode;
        }
@@ -392,7 +500,7 @@ LWZReadByte (GifContext *context)
        if (context->lwz_sp > context->lwz_stack)
                return *--(context->lwz_sp);
 
-       while ((code = GetCode (context, context->lwz_code_size, FALSE)) >= 0) {
+       while ((code = GetCode (context, context->lwz_code_size)) >= 0) {
                if (code == context->lwz_clear_code) {
                        for (i = 0; i < context->lwz_clear_code; ++i) {
                                context->lwz_table[0][i] = 0;
@@ -405,12 +513,14 @@ LWZReadByte (GifContext *context)
                        context->lwz_max_code = context->lwz_clear_code + 2;
                        context->lwz_sp = context->lwz_stack;
                        context->lwz_firstcode = context->lwz_oldcode =
-                               GetCode (context, context->lwz_code_size, FALSE);
+                               GetCode (context, context->lwz_code_size);
                        return context->lwz_firstcode;
                } else if (code == context->lwz_end_code) {
                        int count;
                        unsigned char buf[260];
 
+                       g_error (" DID WE EVER EVER GET HERE\n");
+                       
                        if (ZeroDataBlock)
                                return -2;
 
@@ -434,7 +544,7 @@ LWZReadByte (GifContext *context)
                        if (code == context->lwz_table[0][code]) {
                                /*g_message (_("GIF: circular table entry BIG ERROR\n"));*/
                                /*gimp_quit ();*/
-                               return -1;
+                               return -2;
                        }
                        code = context->lwz_table[0][code];
                }
@@ -460,80 +570,106 @@ LWZReadByte (GifContext *context)
        return code;
 }
 
+
 static void
+gif_set_get_lzw (GifContext *context)
+{
+       context->state = GIF_GET_LZW;
+       context->draw_xpos = 0;
+       context->draw_ypos = 0;
+       context->draw_pass = 0;
+}
+
+static int
 gif_get_lzw (GifContext *context)
 {
        guchar *dest, *temp;
-       gint xpos = 0, ypos = 0, pass = 0;
        gint v;
 
-       context->pixbuf = gdk_pixbuf_new (ART_PIX_RGB,
-                                         context->gif89.transparent,
-                                         8,
-                                         context->width,
-                                         context->height);
+       
+       if (context->pixbuf == NULL) {
+               context->pixbuf = gdk_pixbuf_new (ART_PIX_RGB,
+                                                 context->gif89.transparent,
+                                                 8,
+                                                 context->width,
+                                                 context->height);
+
+               if (context->func)
+                       (* context->func) (context->pixbuf, context->user_data);
+       }
 
        dest = gdk_pixbuf_get_pixels (context->pixbuf);
-       while ((v = LWZReadByte ( context)) >= 0) {
+       while (TRUE) {
+               v = lwz_read_byte (context);
+               if (v < 0) {
+                       return v;
+               }
+               
+
                if (context->gif89.transparent) {
-                       temp = dest + ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + xpos * 4;
+                       temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
                        *temp = context->color_map [0][(guchar) v];
                        *(temp+1) = context->color_map [1][(guchar) v];
                        *(temp+2) = context->color_map [2][(guchar) v];
                        *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 65535);
                } else {
-                       temp = dest + ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + xpos * 3;
+                       temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
                        *temp = context->color_map [0][(guchar) v];
                        *(temp+1) = context->color_map [1][(guchar) v];
                        *(temp+2) = context->color_map [2][(guchar) v];
                }
 
-               xpos++;
-               if (xpos == context->frame_len) {
-                       xpos = 0;
+               context->draw_xpos++;
+               if (context->draw_xpos == context->frame_len) {
+                       context->draw_xpos = 0;
                        if (context->frame_interlace) {
-                               switch (pass) {
+                               switch (context->draw_pass) {
                                case 0:
                                case 1:
-                                       ypos += 8;
+                                       context->draw_ypos += 8;
                                        break;
                                case 2:
-                                       ypos += 4;
+                                       context->draw_ypos += 4;
                                        break;
                                case 3:
-                                       ypos += 2;
+                                       context->draw_ypos += 2;
                                        break;
                                }
 
-                               if (ypos >= context->frame_height) {
-                                       pass++;
-                                       switch (pass) {
+                               if (context->draw_ypos >= context->frame_height) {
+                                       context->draw_pass++;
+                                       switch (context->draw_pass) {
                                        case 1:
-                                               ypos = 4;
+                                               context->draw_ypos = 4;
                                                break;
                                        case 2:
-                                               ypos = 2;
+                                               context->draw_ypos = 2;
                                                break;
                                        case 3:
-                                               ypos = 1;
+                                               context->draw_ypos = 1;
                                                break;
                                        default:
                                                goto done;
                                        }
                                }
                        } else {
-                               ypos++;
+                               context->draw_ypos++;
                        }
                }
-               if (ypos >= context->frame_height)
+               if (context->draw_ypos >= context->frame_height)
                        break;
        }
-
  done:
        /* we got enough data. there may be more (ie, newer layers) but we can quit now */
        context->state = GIF_DONE;
+       return 0;
 }
 
+static void
+gif_set_prepare_lzw (GifContext *context)
+{
+       context->state = GIF_PREPARE_LZW;
+}
 static int
 gif_prepare_lzw (GifContext *context)
 {
@@ -549,10 +685,10 @@ gif_prepare_lzw (GifContext *context)
        context->lwz_end_code = context->lwz_clear_code + 1;
        context->lwz_max_code_size = 2 * context->lwz_clear_code;
        context->lwz_max_code = context->lwz_clear_code + 2;
-
-       GetCode (context, 0, TRUE);
-
        context->lwz_fresh = TRUE;
+       context->code_curbit = 0;
+       context->code_lastbit = 0;
+       context->code_done = FALSE;
 
        for (i = 0; i < context->lwz_clear_code; ++i) {
                context->lwz_table[0][i] = 0;
@@ -562,6 +698,8 @@ gif_prepare_lzw (GifContext *context)
                context->lwz_table[0][i] = context->lwz_table[1][0] = 0;
 
        context->lwz_sp = context->lwz_stack;
+       gif_set_get_lzw (context);
+
        return 0;
 }
 
@@ -612,23 +750,58 @@ gif_init (GifContext *context)
        return 0;
 }
 
+static void
+gif_set_get_frame_info (GifContext *context)
+{
+       context->state = GIF_GET_FRAME_INFO;
+}
+
+static gint
+gif_get_frame_info (GifContext *context)
+{
+       unsigned char buf[9];
+       if (!ReadOK (context, buf, 9)) {
+               return -1;
+       }
+       /* Okay, we got all the info we need.  Lets record it */
+       context->frame_len = LM_to_uint (buf[4], buf[5]);
+       context->frame_height = LM_to_uint (buf[6], buf[7]);
+       if (context->frame_height > context->height) {
+               context->state = GIF_DONE;
+               return -2;
+       }
+
+       context->frame_interlace = BitSet (buf[8], INTERLACE);
+       if (BitSet (buf[8], LOCALCOLORMAP)) {
+               /* Does this frame have it's own colormap. */
+               /* really only relevant when looking at the first frame
+                * of an animated gif. */
+               /* if it does, we need to re-read in the colormap,
+                * the gray_scale, and the bit_pixel */
+               context->bit_pixel = 1 << ((buf[8] & 0x07) + 1);
+               gif_set_get_colormap2 (context);
+               return 0;
+       }
+       gif_set_prepare_lzw (context);
+       return 0;
+       
+}
+
 
 static gint
 gif_get_next_step (GifContext *context)
 {
-       unsigned char buf[16];
        unsigned char c;
-       for (;;) {
+       while (TRUE) {
                if (!ReadOK (context, &c, 1)) {
                        return -1;
                }
-               g_print ("c== %c\n", c);
                if (c == ';') {
                        /* GIF terminator */
                        /* hmm.  Not 100% sure what to do about this.  Should
                         * i try to return a blank image instead? */
                        context->state = GIF_DONE;
-                       return 1;
+                       return -2;
                }
 
                if (c == '!') {
@@ -642,35 +815,10 @@ gif_get_next_step (GifContext *context)
                        /* Not a valid start character */
                        continue;
                }
-
-               if (!ReadOK (context, buf, 9)) {
-                       return -1;
-               }
-
-               /* Okay, we got all the info we need.  Lets record it */
-               context->frame_len = LM_to_uint (buf[4], buf[5]);
-               context->frame_height = LM_to_uint (buf[6], buf[7]);
-               if (context->frame_height > context->height) {
-                       context->state = GIF_DONE;
-                       return 1;
-               }
-
-               context->frame_interlace = BitSet (buf[8], INTERLACE);
-               if (BitSet (buf[8], LOCALCOLORMAP)) {
-                       /* Does this frame have it's own colormap. */
-                       /* really only relevant when looking at the first frame
-                        * of an animated gif. */
-                       /* if it does, we need to re-read in the colormap,
-                        * the gray_scale, and the bit_pixel */
-                       context->bit_pixel = 1 << ((buf[8] & 0x07) + 1);
-                       gif_set_get_colormap2 (context);
-                       return 0;
-               }
-               context->state = GIF_PREPARE_LZW;
+               /* assume it's frame info */
+               gif_set_get_frame_info (context);
                return 0;
        }
-       g_assert_not_reached ();
-       return 1;
 }
 
 
@@ -682,56 +830,53 @@ gif_main_loop (GifContext *context)
        do {
                switch (context->state) {
                case GIF_START:
-                       g_print ("in GIF_START\n");
                        retval = gif_init (context);
                        break;
 
                case GIF_GET_COLORMAP:
-                       g_print ("in GIF_GET_COLORMAP\n");
                        retval = gif_get_colormap (context);
                        if (retval == 0)
                                context->state = GIF_GET_NEXT_STEP;
                        break;
 
                case GIF_GET_NEXT_STEP:
-                       g_print ("in GIF_GET_NEXT_STEP\n");
                        retval = gif_get_next_step (context);
                        break;
 
+               case GIF_GET_FRAME_INFO:
+                       retval = gif_get_frame_info (context);
+                       break;
+
                case GIF_GET_EXTENTION:
-                       g_print ("in GIF_GET_EXTENTION\n");
                        retval = gif_get_extension (context);
                        if (retval == 0)
                                context->state = GIF_GET_NEXT_STEP;
                        break;
 
                case GIF_GET_COLORMAP2:
-                       g_print ("in GIF_GET_COLORMAP2\n");
                        retval = gif_get_colormap (context);
                        if (retval == 0)
-                               context->state = GIF_PREPARE_LZW;
+                               gif_set_prepare_lzw (context);
                        break;
 
                case GIF_PREPARE_LZW:
-                       g_print ("in GIF_PREPARE_LZW\n");
                        retval = gif_prepare_lzw (context);
-                       if (retval == 0)
-                               context->state = GIF_GET_LZW;
                        break;
 
+               case GIF_LZW_FILL_BUFFER:
+                       retval = gif_lzw_fill_buffer (context);
+                       break;
+                       
                case GIF_GET_LZW:
-                       g_print ("in GIF_GET_LZW\n");
-                       gif_get_lzw (context);
-                       retval = 0;
+                       retval = gif_get_lzw (context);
                        break;
 
                case GIF_DONE:
                default:
-                       g_print ("in GIF_DONE\n");
                        retval = 0;
                        goto done;
                };
-       } while (retval == 0);
+       } while ((retval == 0) || (retval == -3));
  done:
        return retval;
 }
@@ -745,10 +890,10 @@ image_load (FILE *file)
        g_return_val_if_fail (file != NULL, NULL);
 
        context = g_new (GifContext, 1);
-       context->lwz_fresh = FALSE;
        context->file = file;
        context->pixbuf = NULL;
        context->state = GIF_START;
+       context->func = NULL;
 
        gif_main_loop (context);
 
@@ -760,14 +905,15 @@ image_begin_load (ModulePreparedNotifyFunc func, gpointer user_data)
 {
        GifContext *context;
 
+       count = 0;
        context = g_new (GifContext, 1);
        context->func = func;
        context->user_data = user_data;
-       context->lwz_fresh = FALSE;
        context->file = NULL;
        context->pixbuf = NULL;
        context->state = GIF_START;
-
+       context->buf = NULL;
+       context->amount_needed = 0;
        return (gpointer) context;
 }
 
@@ -778,6 +924,7 @@ image_stop_load (gpointer data)
 
        if (context->pixbuf)
                gdk_pixbuf_unref (context->pixbuf);
+//     g_free (context->buf);
        g_free (context);
 }
 
@@ -787,17 +934,54 @@ image_load_increment (gpointer data, guchar *buf, guint size)
        gint retval;
        GifContext *context = (GifContext *) data;
 
-       return FALSE;
        if (context->amount_needed == 0) {
                /* we aren't looking for some bytes. */
+               /* we can use buf now, but we don't want to keep it around at all.
+                * it will be gone by the end of the call. */
                context->buf = buf;
                context->ptr = 0;
                context->size = size;
-       } 
+       } else {
+               /* we need some bytes */
+               if (size < context->amount_needed) {
+                       context->amount_needed -= size;
+                       /* copy it over and return */
+                       memcpy (context->buf + context->size, buf, size);
+                       context->size += size;
+                       return TRUE;
+               } else if (size == context->amount_needed) {
+                       memcpy (context->buf + context->size, buf, size);
+                       context->size += size;
+               } else {
+                       context->buf = g_realloc (context->buf, context->size + size);
+                       memcpy (context->buf + context->size, buf, size);
+                       context->size += size;
+               }
+       }
+
        retval = gif_main_loop (context);
-       if (retval == 1)
+
+       if (retval == -2)
                return FALSE;
        if (retval == -1) {
+               /* we didn't have enough memory */
+               /* prepare for the next image_load_increment */
+               if (context->buf == buf) {
+                       g_assert (context->size == size);
+                       context->buf = (guchar *)g_new (guchar, context->amount_needed + (context->size - context->ptr));
+                       memcpy (context->buf, buf + context->ptr, context->size - context->ptr);
+               } else {
+                       /* copy the left overs to the begining of the buffer */
+                       /* and realloc the memory */
+                       memcpy (context->buf, context->buf, context->size - context->ptr);
+                       context->buf = g_realloc (context->buf, context->amount_needed + (context->size - context->ptr));
+               }
+               context->size = context->size - context->ptr;
+               context->ptr = 0;
+       } else {
+               /* we are prolly all done */
+               if (context->buf == buf)
+                       context->buf = NULL;
        }
        return TRUE;
 }